`timescale    1ps/1ps
`default_nettype none
module phy_interface
#(
    DEVICE_TYPE = 0
)
(
    //时钟和复位
    input  wire        resetb,
    input  wire        sclk,
    input  wire        sclk_shift,

    //其他外部相关信号
    input  wire        tx_err_en,
    input  wire        time_1ms,
    input  wire        time_125ms,
    
    //PORTA接口
    input  wire        gp0_rxc,
    input  wire        gp0_rxdv,
    input  wire [3:0]  gp0_rxd,
    output wire        gp0_txc,
    output wire        gp0_txen,
    output wire [3:0]  gp0_txd,
    
    //PORTB接口
    input  wire        gp1_rxc,
    input  wire        gp1_rxdv,
    input  wire [3:0]  gp1_rxd,
    output wire        gp1_txc,
    output wire        gp1_txen,
    output wire [3:0]  gp1_txd,
    
    //给内部的接收接口
    output wire        rec_flag,
    output wire [7:0]  rec_data,
    output wire        rec_error,
    output wire        rec_error_sync,
    
    //内部的发送接口
    input  wire        send_flag,
    input  wire        pre_flag,
    input  wire [7:0]  send_data,
    
    //给内部的其他信号
    output wire [1:0]  rec_vendor,
    output wire        input_active,
    output wire        redu_flag,
    output wire        blank_flag,
    output wire [1:0]  gp0_rx_type,
    output wire [1:0]  gp1_rx_type,
    
    // 收包错误检测
    input  wire        reset_rx_error,
    output wire        gp0_rx_error,
    output wire        gp1_rx_error,

    // 用于收包检测
    output wire        gp0_rx_dv_out,
    output wire        gp1_rx_dv_out,

    output wire        frame_sync,

    //调试用信号输出
    output wire [7:0]  tout
    );

//**************************************************************
//           参数定义
//**************************************************************    
//常数定义
localparam SUB    = 0;       //分控
localparam ASSIST = 1;       //附属设备

//**************************************************************
//           信号定义
//**************************************************************    
wire        gp0_rx_clk,gp0_rx_dv,gp1_rx_clk,gp1_rx_dv;
wire [7:0]  gp0_rx_data,gp1_rx_data;
wire        gp1_tx_clk_t,gp0_tx_en,gp1_tx_en;
wire [7:0]  gp0_tx_data,gp1_tx_data;
wire        gp0_rec_flag,gp0_rec_error,gp0_blank_flag,gp1_rec_flag,gp1_rec_error,gp1_blank_flag;
wire        gp0_send_flag,gp0_pre_flag,gp1_send_flag,gp1_pre_flag;
wire [7:0]  gp0_rec_data,gp1_rec_data,gp0_send_data,gp1_send_data;
wire        gp0_rx_er, gp1_rx_er;

wire        sync_en_0,sync_en_1;//,frame_sync;
wire [21:0] sync_tick_0;
wire [21:0] sync_tick_1;

wire [21:0] current_tick;

reg         sync_en;
reg  [21:0] sync_tick;

//**************************************************************
//           接口逻辑
//**************************************************************    
//PORTA接收接口
RGMII_rec_io rec_io_a(
    .rxc(gp0_rxc),
    .rxdv(gp0_rxdv),
    .rxd(gp0_rxd),        
        
    .rx_clk(gp0_rx_clk),
    .rx_dv(gp0_rx_dv),
    .rx_data(gp0_rx_data),

    .rx_er(gp0_rx_er),
    .rx_crs(),
    .rx_col()
);
        
//检测PORTA接收时钟频率
rx_clk_check    rx_clk_check_p0(
    .sclk(sclk),
    .rx_clk(gp0_rx_clk),    
    .clk_type(gp0_rx_type),
    .mega_clk_sel()
    );

//PORTA发送接口
RGMII_trans_io trans_io_a(
    .tx_clk(sclk),
    .tx_en(gp0_tx_en),
    .tx_data(gp0_tx_data),

    .tclk(sclk_shift),

    .txc(gp0_txc),
    .txen(gp0_txen),
    .txd(gp0_txd)        
);

//PORTB接收接口
RGMII_rec_io rec_io_b(
    .rxc(gp1_rxc),
    .rxdv(gp1_rxdv),
    .rxd(gp1_rxd),        
        
    .rx_clk(gp1_rx_clk),
    .rx_dv(gp1_rx_dv),
    .rx_data(gp1_rx_data),

    .rx_er(gp1_rx_er),
    .rx_crs(),
    .rx_col()
);

//检测PORTB接收时钟频率
rx_clk_check rx_clk_check_p1(
    .sclk(sclk),
    .rx_clk(gp1_rx_clk),    
    .clk_type(gp1_rx_type),
    .mega_clk_sel()
    );

//PORTB发送接口
RGMII_trans_io trans_io_b(
    .tx_clk(sclk),
    .tx_en(gp1_tx_en),
    .tx_data(gp1_tx_data),

    .tclk(sclk_shift),

    .txc(gp1_txc),
    .txen(gp1_txen),
    .txd(gp1_txd)
    );

//网卡调屏帧同步信号
self_sync self_sync_inst
(
    .I_sclk(sclk),  // 125M
    .I_rst_n(resetb),
    .I_sync_en(sync_en),
    .I_sync_tick(sync_tick),
    .O_frame_sync(frame_sync),
    .O_current_tick(current_tick)
);

always @(posedge sclk or negedge resetb)
    if(!resetb)
        sync_en <= 1'b0;
    else if(sync_en_0 || sync_en_1)
        sync_en <= 1'b1;
    else 
        sync_en <= 1'b0;

always @(posedge sclk or negedge resetb)
    if(!resetb)
        sync_tick <= 0;
    else if(sync_en_0)
        sync_tick <= sync_tick_0;
    else if(sync_en_1)
        sync_tick <= sync_tick_1;
    else
        sync_tick <= 0;

//PORTA控制模块
v8_cascade_ctrl_01
#(
    .DEVICE_TYPE(DEVICE_TYPE)
) cascade_ctrl_a(
    .resetb(resetb),
    .sclk(sclk),

    .rx_clk(gp0_rx_clk),
    .rx_dv(gp0_rx_dv),
    .rgmii_rx_data(gp0_rx_data),
    .rx_type(gp0_rx_type),
    
    .rec_flag(gp0_rec_flag),
    .rec_data(gp0_rec_data),
    .rec_error(gp0_rec_error),
    .blank_flag(gp0_blank_flag),

    .i_tx_en(gp1_send_flag),
    .i_tx_pre(gp1_pre_flag),
    .i_tx_data(gp1_send_data),
    
    .tx_clk(sclk),
    .tx_en(gp1_tx_en),
    .tx_data(gp1_tx_data),
    .tx_err_en(tx_err_en),

    .sync_en(sync_en_0),
    .sync_tick(sync_tick_0),
    .current_tick(current_tick),

    .tout()
);

//PORTB控制模块
v8_cascade_ctrl_01 
#(
    .DEVICE_TYPE(DEVICE_TYPE)
) cascade_ctrl_b(
    .resetb(resetb),
    .sclk(sclk),

    .rx_clk(gp1_rx_clk),
    .rx_dv(gp1_rx_dv),
    .rgmii_rx_data(gp1_rx_data),
    .rx_type(gp1_rx_type),
    
    .rec_flag(gp1_rec_flag),
    .rec_data(gp1_rec_data),
    .rec_error(gp1_rec_error),
    .blank_flag(gp1_blank_flag),

    .i_tx_en(gp0_send_flag),
    .i_tx_pre(gp0_pre_flag),
    .i_tx_data(gp0_send_data),
    
    .tx_clk(sclk),
    .tx_en(gp0_tx_en),
    .tx_data(gp0_tx_data),
    .tx_err_en(tx_err_en),

    .sync_en(sync_en_1),
    .sync_tick(sync_tick_1),
    .current_tick(current_tick),

    .tout()
);

//端口级联方向选择
v8_port_select_01 port_select(
    .resetb(resetb),
    .sclk(sclk),
    
    .flash_ms(time_1ms),
    .time_125ms(time_125ms),

    .gp0_rec_flag(gp0_rec_flag),
    .gp0_rec_data(gp0_rec_data),
    .gp0_rec_error(gp0_rec_error),
    .gp0_blank_flag(gp0_blank_flag),
    
    .gp1_rec_flag(gp1_rec_flag),
    .gp1_rec_data(gp1_rec_data),
    .gp1_rec_error(gp1_rec_error),
    .gp1_blank_flag(gp1_blank_flag),
    
    .rec_flag(rec_flag),
    .rec_data(rec_data),
    .rec_error(rec_error),
    .rec_vendor(rec_vendor),
    .rec_error_sync(rec_error_sync),
    
    .send_flag(send_flag),
    .pre_flag(pre_flag),
    .send_data(send_data),
    
    .blank_flag(blank_flag),
    .redu_flag(redu_flag),
    
    .gp0_send_flag(gp0_send_flag),
    .gp0_pre_flag(gp0_pre_flag),
    .gp0_send_data(gp0_send_data),
    
    .gp1_send_flag(gp1_send_flag),
    .gp1_pre_flag(gp1_pre_flag),
    .gp1_send_data(gp1_send_data),
    
    .input_active(input_active),
    
    .tout()
    );

assign tout = 8'd0;

// rgmii_error_check
rgmii_error_check chk_gp0 (
    .rxc    ( gp0_rx_clk ),
    .rst_n  ( resetb & !reset_rx_error ),
    .rxdv   ( gp0_rx_dv ),
    .rxer   ( gp0_rx_er ),
    .error  ( gp0_rx_error )
);

// rgmii_error_check
rgmii_error_check chk_gp1 (
    .rxc    ( gp1_rx_clk ),
    .rst_n  ( resetb & !reset_rx_error ),
    .rxdv   ( gp1_rx_dv ),
    .rxer   ( gp1_rx_er ),
    .error  ( gp1_rx_error )
);

reg  [1:0]  gp0_rx_dv_sr;
reg  [1:0]  gp1_rx_dv_sr;

assign gp0_rx_dv_out = gp0_rx_dv_sr[1];
assign gp1_rx_dv_out = gp1_rx_dv_sr[1];

always @(posedge gp0_rx_clk or negedge resetb) begin
    if (!resetb)
        gp0_rx_dv_sr <= 1'b0;
    else
        gp0_rx_dv_sr <= {gp0_rx_dv_sr[0], gp0_rx_dv};
end

always @(posedge gp1_rx_clk or negedge resetb) begin
    if (!resetb)
        gp1_rx_dv_sr <= 1'b0;
    else
        gp1_rx_dv_sr <= {gp1_rx_dv_sr[0], gp1_rx_dv};
end

endmodule

`default_nettype wire


